package backend;

import java.util.StringTokenizer;

import backend.instructions.*;
import backend.instructions.branch_jump.*;
import backend.instructions.i_type.*;
import backend.instructions.load_store.*;
import backend.instructions.r_type.*;

public class Parser {

	RegistersMap RegMap;
	ProgramCode code;
	StringTokenizer Lines;
	StringTokenizer Word;
	String codeLines;

	public Parser(RegistersMap RegMap) {
		this.RegMap = RegMap;
	}

	public ProgramCode parse() {
		code = new ProgramCode();
		Instruction temp = null;
		Lines = new StringTokenizer(codeLines.toUpperCase(), "\n");
		String line;
		int index = 1;
		while (Lines.hasMoreTokens()) {
			line = Lines.nextToken();
			Word = new StringTokenizer(line, " ,");
			String op = Word.nextToken().toLowerCase();
			String rd = "", rs = "", rt = "";
			if (Word.countTokens() == 1) {
				String target = Word.nextToken();
				if ("j".equals(op))
					temp = new J(op, target, index, RegMap);
				else if ("jr".equals(op))
					temp = new Jr(op, target, index, RegMap);
				else if ("jal".equals(op))
					temp = new Jal(op, target, index, RegMap);
				continue;
			}
			if (Word.countTokens() == 2) {
				rt = Word.nextToken();
				String tmp = Word.nextToken();
				String offset = tmp.substring(0, tmp.indexOf("("));
				rs = tmp.substring(tmp.indexOf("(") + 1, tmp.indexOf(")"));
				if ("lw".equals(op))
					temp = new Load(op, rs, rt, offset, index, RegMap);
				else if ("sw".equals(op))
					temp = new Store(op, rs, rt, offset, index, RegMap);
				continue;
			}
			if (Word.countTokens() == 3) {

				if ("beq".equals(op)) {
					rs = Word.nextToken();
					rt = Word.nextToken();
					String offset = Word.nextToken();
					temp = new Beq(op, rs, rt, offset, index, RegMap);
					continue;
				} else if ("bne".equals(op)) {
					String offset = Word.nextToken();
					temp = new Bne(op, rs, rt, offset, index, RegMap);
					continue;
				} else {
					rd = Word.nextToken();
					rs = Word.nextToken();
					rt = Word.nextToken();
				}
			}

			switch (op) {
			case "add":
				temp = new Add(op, rs, rt, rd, index, RegMap);
				break;
			case "sub":
				temp = new Sub(op, rs, rt, rd, index, RegMap);
				break;
			case "sll":
				temp = new Sll(op, rs, rt, rd, index, RegMap);
				break;
			case "srl":
				temp = new Srl(op, rs, rt, rd, index, RegMap);
				break;
			case "and":
				temp = new And(op, rs, rt, rd, index, RegMap);
				break;
			case "or":
				temp = new Or(op, rs, rt, rd, index, RegMap);
				break;
			case "nor":
				temp = new Nor(op, rs, rt, rd, index, RegMap);
				break;
			case "slt":
				temp = new Slt(op, rs, rt, rd, index, RegMap);
				break;
			case "sltu":
				temp = new Sltu(op, rs, rt, rd, index, RegMap);
				break;
			case "addi":
				temp = new Addi(op, rs, rt, rd, index, RegMap);
				break;
			case "andi":
				temp = new Andi(op, rs, rt, rd, index, RegMap);
				break;
			case "ori":
				temp = new Ori(op, rs, rt, rd, index, RegMap);
				break;
			case "slti":
				temp = new Slti(op, rs, rt, rd, index, RegMap);
				break;
			case "sltui":
				temp = new Sltiu(op, rs, rt, rd, index, RegMap);
				break;
			}
			code.addInstruction(temp);
			index++;
		}
		code.setFinished();
		return code;
	}
}
